import { dateUtil } from './dateUtil';
//农历资源数据结构
//每行为一年,一行包含52字节(没有回车符),数字分为两部分,前4字节为第一部分,后48字节为第二部分
//第1第2字节为一个无符号16位整数(注意高位在右),保存12或13个月大小月数据(还包含本年是否为闰年)
//第3字节为闰月数,此年无闰月值为0,注意闰月的数值指向闰月的内部月数,比如:闰四月的时候此值为5
//第4字节为正月初一相对于元旦的偏移天数
//后面的48字节,每2字节为一个无符号16位整数,保存24个节气每节气的日时分(公历)
export type JieQiItem = {
	name : string,
	date : Date,
	index : number,
}
export class JieQi {
	Name : string;
	Date : Date;
	Index : number;
	constructor(name : string, date : Date, index : number) {
		this.Name = name;
		this.Date = date;
		this.Index = index;
	}
	/**
	 * @description 从节气索引 ( 0 ~ 23 ) 获取节气名称
	 * @param {int} theJieQiIndex 节气索引 ( 0 ~ 11 )
	 * @return {String}
	 */
	static getJieQiName(theJieQiIndex : number) : string {
		return JieQi.JieQiResource[theJieQiIndex];
	};
	/**
	 * @description 从指定的公历日期范围获取包含的所有节气信息数组(节气信息: name=节气名称,date=节气时间点,index=节气索引)
	 * @param {Object} startDate
	 * @param {Object} endDate
	 */
	static getJieQiArrayByRange(startDate : Date, endDate : Date) : JieQiItem[] {
		let dStart = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(), -1, -5, 0, 0);
		let dEnd = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate(), 23, 5, 0, 0);
		let darray : JieQiItem[] = new Array();
		let dindex = startDate.getMonth() * 2;
		let dyear = dStart.getFullYear();
		let dJieQi = JieQi.getJieQi(dyear, dindex);
		while (dJieQi <= dEnd) {
			if (dJieQi >= dStart) {
				darray.push({
					name: JieQi.getJieQiName(dindex),
					date: dJieQi,
					index: dindex
				})
			}
			dindex++;
			if (dindex > 23) {
				dindex = 0;
				dyear++;
			}
			dJieQi = JieQi.getJieQi(dyear, dindex);
		}
		return darray;
	};
	/**
	 * 根据精确到分钟的公历日期, 计算它所在的节气. 返回节气的对象
	 */
	static getJieQiByDate(date : Date) : JieQi {
		let year = date.getFullYear();
		let monthIndex = date.getMonth();
		let day = date.getDate();
		let JieqiIndex = date.getMonth() * 2;
		if (day > 17) JieqiIndex++;
		let startDay = JieQi.getJieQiStart(JieqiIndex);
		let minute = JieQi.getJieQiAdjust(year, JieqiIndex);
		let jqDate = new Date(year, monthIndex, startDay, 0, minute);
		if (date < jqDate) {
			JieqiIndex--;
			if (JieqiIndex < 0) {
				JieqiIndex = 23;
				year--;
			}
			startDay = JieQi.getJieQiStart(JieqiIndex);
			minute = JieQi.getJieQiAdjust(year, JieqiIndex);
			jqDate = new Date(year, Math.floor(JieqiIndex / 2), startDay, 0, minute);
		}
		return new JieQi(JieQi.getJieQiName(JieqiIndex), jqDate, JieqiIndex);
	}
	/**
	 * 根据精确到分钟的公历日期, 计算它所在的节气索引. 返回的值可能为负数, 表示上一年的节气
	 */
	static getJieQiIndexByDate(date : Date) : number {
		let year = date.getFullYear();
		let monthIndex = date.getMonth();
		let day = date.getDate();
		let JieqiIndex = date.getMonth() * 2;
		if (day > 17) JieqiIndex++;
		let startDay = JieQi.getJieQiStart(JieqiIndex);
		let minute = JieQi.getJieQiAdjust(year, JieqiIndex);
		if (date < new Date(year, monthIndex, startDay, minute)) JieqiIndex--;
		return JieqiIndex;
	}
	/**
	 * @description 节气名称数组(24个),从小寒=0开始为
	 * @type {String}
	 */
	static JieQiResource : string[] = [
		"小寒", "大寒",
		"立春", "雨水",
		"惊蛰", "春分",
		"清明", "谷雨",
		"立夏", "小满",
		"芒种", "夏至",
		"小暑", "大暑",
		"立秋", "处暑",
		"白露", "秋分",
		"寒露", "霜降",
		"立冬", "小雪",
		"大雪", "冬至"];

	/**
	 * 从节气索引（0 - 23）计算节气月份（0 - 11）。  
	 * 注意节气索引是从小寒开始的，它是12月, 应该返回11, (负数或超出23也能正常计算)
	 */
	static getJieqiMonthFromJieqiIndex(jieqiIndex : number) {
		return ((jieqiIndex + 22) % 24) >> 1;
	}
	/**
	 * 获取指定节气从标定日开始的偏移分钟数
	 */
	static getJieQiAdjust(year : number, jieqiIndex : number) : number {
		if (year < 1500 || year > 2499) throw new Error("节气年份必须在1500~2499之间");
		//每年有48个字符，10年为一行， 总是从尾数0的年份开始
		let startPoint = (year % 10) * 48 + jieqiIndex * 2;
		let index = Math.floor(year / 10 - 150 + 4);
		// console.log("getJieQiAdjust: year=" + (year?.toString() ?? "") + " jieqi=" + (jieqiIndex?.toString() ?? ""));
		let code = dateUtil.listdate[index].substring(startPoint, startPoint + 2);
		return dateUtil.fromWord93(code);
	}
	/**
	 * 获取指定节气的开始范围标定日
	 */
	static getJieQiStart(jieqiIndex : number) : number {
		let startPoint = (jieqiIndex >> 1) * 3 + (jieqiIndex % 2);
		return parseInt(dateUtil.listdate[2].substring(startPoint, startPoint + 1 + (jieqiIndex % 2)))
	}
	/**
	 * 获取指定节气的截止范围标定日
	 */
	static getJieQiEnd(jieqiIndex : number) : number {
		let startPoint = (jieqiIndex >> 1) * 3 + (jieqiIndex % 2);
		return parseInt(dateUtil.listdate[3].substring(startPoint, startPoint + 1 + (jieqiIndex % 2)))
	}
	/**
	 * @description 获取指定节气的时间点,年份必须在 1500 ~ 2499之间
	 * @param {int} theYear 年份,必须在 1500 ~ 2499之间
	 * @param {int} theJieQiIndex 节气索引 ( 0 ~ 23 ),小寒为0,大寒为1,立春为2,以此类推
	 * @return {Date}
	 */
	static getJieQi(theYear : number, theJieQiIndex : number) : Date {
		if (theJieQiIndex < 0 || theJieQiIndex > 23) {
			throw new Error("节气索引必须在0~23之间");
		}
		let startDay = JieQi.getJieQiStart(theJieQiIndex);
		let minute = JieQi.getJieQiAdjust(theYear, theJieQiIndex);
		return new Date(theYear, theJieQiIndex >> 1, startDay, 0, minute);
	}

}